

/**
 * _  依赖全局 lodash 库
 */

/** 
 * @class  基础配置基类
 * */
class BaseConfig {
  /**  表单容器列数 */
  cols = 1
  /** 表单容器行间距，百分比或者px */
  rowGap = '0px'
  /** 表单容器列间距，百分比或者px */
  columnGap = '5px'
  /**  表单标题 */
  title = ''  // 表单标题
  /**表单  max-width,不会超过当前 表单容器宽度 */
  width = '100%'
}
/**生成唯一key */
function getRandomKey() {
  return `k_${Math.random().toString(36).substring(2,15)}`
}


/**
 * @class   表单配置
 * */

class FormConfig extends BaseConfig {
  /* 表单中容器中，无表单项时的提示文字 */
  emptyText = ''     //无内容时显示文字
  /**表单 能否编辑 ，通过css 属性 pointer-events: none 禁用，优先级高于所有 FormItemConfig中的 readonly属性 */
  readonly = false   //表单是否只读，无法编辑
  /** el-form 表单控件尺寸 */
  size = 'mini'
  /** vue.dragable 配置，表单控件 可拖拽 功能*/
  draggable = false
  /** vue.dragable  配置，表单控件的 排序 功能 */
  sortable = false
  /** el-form 的rules */
  rules = {}        // 表单的rules
  /**表单项的  可选择性，用于在编辑状态，选择需要编辑的表单项 */
  selectable = false
  /** 表单数据*/
  formData = {}
  /**@type {'left'|'top'}  */
  labelPosition = 'left'
  /**表单label的宽度 */
  labelWidth = 'auto'
  /**表单标签的后缀 */
  labelSuffix = ':'         // 
  /**@type {FormItemConfig[]}   表单项的 配置，用于生成表单项元素 */
  formItems = []
  /** 绑定的 el-form 组件的 ref ,用于获取 el-form 信息和方式*/
  elFormRef
  selectedItem = null
  /**
  * @param {FormConfig} option
  */
  constructor(option) {
    super()
    _.merge(this,option)
  }


  resetFormData(newFormData) {
    if (newFormData) this.formData = newFormData
    else this.formData = {}
  }
  resetFormItems(newFormItems) {
    if (Array.isArray(newFormItems)) this.formItems = newFormItems
    else this.formItems = []
  }

  /**
   * 用dataKey表示表单数据，适用于提交的数据
   */
  get formDataWithDataKey() {
    const result = {}
    for (let key in this.formData) {
      const item = this.formItems.find(item => item.key == key)
      if (!item) continue
      result[item.dataKey] = this.formData[key]
    }
    return result
  }

  /**
   * 生成用于预览的表单配置json
   * @returns 
   */
  getRreviewFormConfigJson() {
    /**@type {FormConfig} */
    const _formConfig = _.cloneDeep(this)
    _formConfig.formItems.forEach(item => {
      delete item.configurableFieldItems
      delete item.defaultConfigurableFields
      // delete item._option
    })
    _formConfig.selectable = false
    _formConfig.sortable = false
    _formConfig.draggable = false
    _formConfig.elFormRef = null
    _formConfig.selectedItem = null
    // _formConfig.readonly = true

    console.log('res',_formConfig)
    return JSON.stringify(_formConfig)
  }
  getFormConfigJson() {
    const _formConfig = _.cloneDeep(this)
    return JSON.stringify(_formConfig)
  }



}



/**  
 * @class  ConfigurableFields
 * 可配置字段，ConfigurableFields 适用于CompBar中的注册组件，即 AllComps中的组件需要 ConfigurableFields，用于定义生成 在组件设置板块 的内容
 * ConfigurableFields 配置字段会根据 ConfigurableAttrFieldComps已注册的组件生成默认的configurableFieldItems，再 合并到configurableFieldItems
  */
class ConfigurableFields {
  /** defaultConfigurableFields  默认配置字段，是所有AllComps 组件的基础配置字段 */
  _defaultConfigurableFields = ['label','required','dataKey','title','readonly','span','rules','hasBorder'] // 默认可配置字段
  defaultConfigurableFields = []
  /**@type {FormItemConfig[]}  配置字段的配置组件*/
  configurableFieldItems = []

  /** 是否可配置 ，即配置信息是否生效*/
  configurable = true
  /**
   * 合并可配置字段,包括 配置字段 defaultConfigurableFields + _defaultConfigurableFields
   */
  mergeConfigurableFields() {
    this.defaultConfigurableFields = [...new Set(this._defaultConfigurableFields.concat(this.defaultConfigurableFields))]
  }

}


/**
 * @class 
 * 表单项 的配置类
 * @extends ConfigurableFields
 */
class FormItemConfig extends ConfigurableFields {


  /**
   * 当通过 vue.draggable 拖拽时，从compBar到中间表单展示部分，需要克隆 当前拖动的表单项
   * 并且需要 初始化一些 key ,dataKey 
   * @returns {FormItemConfig}
   */
  deepClone() {

    /** @type {FormItemConfig} item  */
    const item = _.cloneDeep(this)
    item.key = getRandomKey()
    item.dataKey = item.key
    return item
  }

  /** 表单项是否显示边框 */
  hasBorder = false
  /** 当前控件所占容器的栅格数，不得大于容器配置FormConfig 中总栅格数 cols */
  span = 1
  /**控件的label标签*/
  label = 'label'
  /**
   * 
   * 渲染组件 form-panel 中 component.is 的值
   * 可以为已注册字符串组件名，或者是一个组件实例构造函数 
   * 优先级高于templateStr
   * */
  compName
  /**
   * 在渲染组件 form-panel中，会使用 Vue.extend({ template:templateStr }) 生成组件实例
   * 
   * 并通过 component.is 动态渲染，attrs 属性作也会作为 透传属性传入，可在 templateStr 通过$attrs 去使用 ，
   * 
   * 和compName 属性互斥，优先级低于 compName
   * 
   * 适用于生成简单的组件，若组件非常复杂，建议使用注册组件后使用 compName 
   *  */
  templateStr
  /**控件的标题,若控件元素在 compBar展示时，需要显示标题 */
  title
  /**控件的提示信息，当鼠标悬停控件时，可用显示 帮助文本 */
  helpText
  /**控件 能否编辑 ，通过css 属性 pointer-events: none 禁用，优先级低于 FormConfig中的 readonly属性 */
  readonly = false
  /**控件是否必填,el-form-item 的 required 属性，若设置rules的必填属性 ,会覆盖此属性 */
  required = false
  /**当前控件的唯一主键key */
  key = getRandomKey()
  /**用于传输数据时的key键，默认为key */
  dataKey = this.key


  /** 若 FormConfig中 定义了 rules  ，则控件的rules 不会生效 */
  rules = []
  /** 
   * 当提供compName  时，attrs 会通过 v-bind="attrs" 传递给 组件
   * 当提供 templateStr 时，可在templateStr 中 通过$attrs 来使用
   * */
  attrs = { placeholder: '请输入' }

  /**
   * @deprecated 定义在 表单引擎组件： form-panel 内的 转换函数，在v-model 触发set 时，转换值，已废弃
   * @type {(oldVal:any)=>any} 转换函数,当使用 templateStr 作为模板时，可 使用transform 转换v-model 修改的值*/
  transform
  /**
   * @param {FormItemConfig} option
   */
  constructor(option) {
    super()
    _.merge(this,option)
    this.init()
  }
  init() {
    this.mergeConfigurableFields()
    /**初始化title */
    this.title ||= (this.dataKey || this.label)
  }

}






/**
 *  comp-bar 组件
 */
class CompBar extends BaseConfig {
  /**@type {FormConfig[]} */
  parts = []
  /**
   * @param {CompBar} option
   */
  constructor(option) {
    super()
    _.merge(this,option)

  }
}







export {
  BaseConfig,CompBar,FormConfig,FormItemConfig,getRandomKey
}

window.$FEconfig = {
  BaseConfig,CompBar,FormConfig,FormItemConfig,getRandomKey
}


